import base64
import os
import tempfile
import uuid

import cv2
import numpy as np
from flask import current_app, request

from configs.global_config import global_config
from controllers.base_controller import BaseController
from insightface_modules.face_matching import FaceMatching
from entity.face_types import ValidMetrics
from utils.api_response_utils import create_error_response, create_success_response


class FaceMatchingController(BaseController):
    """人脸匹配控制器，处理人脸匹配相关请求"""

    def __init__(self, import_name):
        super().__init__("face_matching", import_name, url_prefix="")
        self.face_matcher = FaceMatching()
        global_config.initialize()
        print(global_config.raw_config)  # 打印原始配置对象以验证初始化

    def _two_images_process(self, image1_data, image2_data):
        """
        处理两张图片的人脸匹配请求
        Args:
            image1_base64 (str): 第一张图片的base64编码
            image2_base64 (str): 第二张图片的base64编码
            metric (str): 相似度度量方法
        Returns:
            dict: 匹配结果
        """
        temp_dir = tempfile.gettempdir()
        image1_path = os.path.join(temp_dir, f"image1_{uuid.uuid4()}.jpg")
        image2_path = os.path.join(temp_dir, f"image2_{uuid.uuid4()}.jpg")

        # 将图片数据写入临时文件
        with open(image1_path, "wb") as f:
            f.write(image1_data)
        with open(image2_path, "wb") as f:
            f.write(image2_data)

        return image1_path, image2_path

    def register_routes(self):
        """注册路由"""

        @self.route("/match_two_faces", methods=["POST"])
        @self.validate_json_request()
        @self.swagger_from("swagger_docs/face_matching/match_two_faces.yml")
        def api_match_two_faces():
            try:
                data = self._param_data_check(request.parsed_data)
                if data is not None:
                    return data  # 如果数据无效，返回错误响应
                data = request.parsed_data

                image1_base64 = data.get("image1_base64")
                image2_base64 = data.get("image2_base64")
                metric = data.get("metric", "cosine")  # 默认使用余弦相似度
                threshold = data.get("threshold", 0.6)  # 相似度阈值
                det_thresh = data.get("det_thresh", 0.5)  # 检测置信度阈值

                # 解码base64图片数据
                try:
                    image1_data = base64.b64decode(image1_base64)
                    image2_data = base64.b64decode(image2_base64)
                except Exception as e:
                    return create_error_response(400, f"base64解码失败: {str(e)}")

                # 保存为临时文件
                image1_path, image2_path = self._two_images_process(
                    image1_data, image2_data
                )

                # 调用人脸匹配服务
                result = self.face_matcher.match_two_faces(
                    image1_path,
                    image2_path,
                    metric=metric,
                    threshold=threshold,
                    det_thresh=det_thresh,
                )

                # 删除临时文件
                try:
                    os.remove(image1_path)
                    os.remove(image2_path)
                except Exception as e:
                    self.logger.warning(f"删除临时文件失败: {str(e)}")

                return create_success_response("人脸匹配完成", result)
            except Exception as e:
                self.logger.error(f"人脸匹配失败: {str(e)}")
                import traceback

                self.logger.error(traceback.format_exc())
                return create_error_response(500, f"服务器内部错误: {str(e)}")

        @self.route("/match_face_to_targets", methods=["POST"])
        @self.validate_json_request()
        @self.swagger_from("swagger_docs/face_matching/match_face_to_targets.yml")
        def api_match_face_to_targets():
            try:
                data = request.parsed_data
                source_image_base64 = data.get("source_image_base64")
                target_images_base64 = data.get("target_images_base64")
                metric = data.get("metric", "cosine")  # 默认使用余弦相似度
                similarity_threshold = data.get(
                    "similarity_threshold", 0.5
                )  # 默认阈值为0.5
                det_thresh = data.get("det_thresh", 0.5)  # 检测置信度阈值

                # 验证参数
                if not source_image_base64:
                    return create_error_response(
                        400,
                        "参数source_image_base64的值为空，请提供有效的base64编码的图片数据",
                    )
                if not target_images_base64 or not isinstance(
                    target_images_base64, list
                ):
                    return create_error_response(
                        400,
                        "参数target_images_base64必须是一个非空数组，每个元素包含一张图片的base64编码",
                    )

                max_batch_size = global_config.get("insightface.max_batch_size", 100)

                if (
                    len(target_images_base64) > max_batch_size
                ):  # 设置一个合理的批处理上限
                    return create_error_response(
                        400,
                        f"一次请求最多处理{max_batch_size}张目标图片，当前请求包含{len(target_images_base64)}张图片",
                    )

                # 解码并保存源图片
                try:
                    source_image_data = base64.b64decode(source_image_base64)
                    source_nparr = np.frombuffer(source_image_data, np.uint8)
                    source_img = cv2.imdecode(source_nparr, cv2.IMREAD_COLOR)

                    if source_img is None:
                        return create_error_response(
                            400,
                            "source_image_base64解码后的图片数据无效，请检查图片数据是否正确",
                        )
                except Exception as e:
                    return create_error_response(400, f"源图片base64解码失败: {str(e)}")

                # 创建临时目录存放目标图片
                unique_id = uuid.uuid4()
                temp_dir = tempfile.mkdtemp()
                # 在临时目录下创建 src_temp 子目录
                src_temp_dir = os.path.join(temp_dir, "src_temp")
                os.makedirs(src_temp_dir, exist_ok=True)
                source_image_path = os.path.join(
                    src_temp_dir, f"source_image_{unique_id}.jpg"
                )
                cv2.imwrite(source_image_path, source_img)

                # 解码并保存所有目标图片
                target_image_paths = []
                for i, target_base64 in enumerate(target_images_base64):
                    try:
                        target_data = base64.b64decode(target_base64)
                        target_nparr = np.frombuffer(target_data, np.uint8)
                        target_img = cv2.imdecode(target_nparr, cv2.IMREAD_COLOR)

                        if target_img is None:
                            continue  # 跳过无效图片

                        # 在临时目录下创建 tar_temp 子目录
                        tar_temp_dir = os.path.join(temp_dir, "tar_temp")
                        os.makedirs(tar_temp_dir, exist_ok=True)
                        target_path = os.path.join(
                            tar_temp_dir, f"target_{i}_{unique_id}.jpg"
                        )
                        cv2.imwrite(target_path, target_img)
                        target_image_paths.append(target_path)
                    except:
                        continue  # 跳过解码失败的图片

                if not target_image_paths:
                    # 清理临时文件
                    os.remove(source_image_path)
                    os.rmdir(temp_dir)
                    return create_error_response(400, "所有目标图片都无效或解码失败")

                # 设置相似度阈值（可选）
                self.face_matcher.similarity_threshold = 0.5
                # 执行人脸匹配
                match_result = self.face_matcher.match_face_to_targets(
                    source_image_path,
                    tar_temp_dir,  # 使用目标图片的子目录，而不是整个临时目录
                    metric,
                    similarity_threshold,
                    det_thresh,
                )

                # 清理临时文件
                for path in target_image_paths:
                    os.remove(path)
                os.remove(source_image_path)
                # 删除子目录
                os.rmdir(src_temp_dir)
                os.rmdir(tar_temp_dir)
                os.rmdir(temp_dir)

                # 构建响应消息
                matched_count = match_result.get("matched_count", 0)
                total_targets = match_result.get("total_targets", 0)

                if "error" in match_result:
                    return create_error_response(422, match_result["error"])

                message = f"人脸匹配完成，共匹配{total_targets}张目标图片，其中{matched_count}张匹配成功"

                return create_success_response(message, match_result)

            except Exception as e:
                current_app.logger.error(
                    f"人脸匹配过程中发生错误: {str(e)}", exc_info=True
                )
                return create_error_response(500, f"服务器内部错误: {str(e)}")

        @self.route("/match_face_features", methods=["POST"])
        @self.validate_json_request()
        @self.swagger_from("swagger_docs/face_matching/match_face_features.yml")
        def api_match_face_features():
            try:
                data = request.parsed_data
                source_feature = data.get("source_feature")
                target_feature = data.get("target_feature")
                metric = data.get("metric", "cosine")  # 默认使用余弦相似度
                similarity_threshold = data.get(
                    "similarity_threshold", 0.5
                )  # 默认阈值为0.5

                # 验证参数
                if not source_feature:
                    return create_error_response(
                        400, "参数source_feature的值为空，请提供有效的人脸特征数据"
                    )
                if not target_feature:
                    return create_error_response(
                        400, "参数target_feature的值为空，请提供有效的人脸特征数据"
                    )
                if (
                    not isinstance(similarity_threshold, (int, float))
                    or not 0 <= similarity_threshold <= 1
                ):
                    return create_error_response(
                        400, "参数similarity_threshold必须是0到1之间的数值"
                    )

                # 验证metric参数
                if metric not in ValidMetrics:
                    return create_error_response(
                        400, f"参数metric的值无效，有效值为: {', '.join(ValidMetrics)}"
                    )

                try:
                    # 将特征数据转换为numpy数组
                    source_embedding = np.array(source_feature)
                    target_embedding = np.array(target_feature)

                    # 计算相似度
                    similarity = self.face_matcher.compute_similarity(
                        source_embedding, target_embedding, metric=metric
                    )
                    # 计算匹配率
                    match_rate = similarity * 100

                    # 判断是否匹配
                    is_matched = similarity >= similarity_threshold

                    # 构建响应结果
                    result = {
                        "matched": is_matched,
                        "match_rate": match_rate,
                        "similarity": similarity,
                        "threshold": similarity_threshold,
                        "metric": metric,
                    }

                    # 构建响应消息
                    if result["matched"]:
                        message = f"人脸特征匹配成功，相似度: {match_rate:.2f}%（阈值: {similarity_threshold * 100:.0f}%）"
                    else:
                        message = f"人脸特征不匹配，相似度: {match_rate:.2f}%（阈值: {similarity_threshold * 100:.0f}%）"

                    return create_success_response(message, result)
                except Exception as e:
                    return create_error_response(422, f"处理特征数据时出错: {str(e)}")
            except Exception as e:
                self.logger.error(f"人脸特征匹配失败: {str(e)}")
                return create_error_response(500, f"服务器内部错误: {str(e)}")

        @self.route("/match_face_to_faces", methods=["POST"])
        @self.validate_json_request()
        @self.swagger_from("swagger_docs/face_matching/match_face_to_faces.yml")
        def api_match_face_to_faces():
            try:
                # 检查传入的数据参数是否有效
                data = self._param_data_check(request.parsed_data)
                if data is not None:
                    return data  # 如果数据无效，返回错误响应
                data = request.parsed_data  # 如果数据有效，继续处理

                image1_base64 = data.get("image1_base64")
                image2_base64 = data.get("image2_base64")
                metric = data.get("metric", "cosine")  # 默认使用余弦相似度
                threshold = data.get("threshold", 0.6)  # 调整默认阈值为0.6
                det_thresh = data.get("det_thresh", 0.5)  # 检测置信度阈值

                # 解码base64图片数据
                try:
                    image1_data = base64.b64decode(image1_base64)
                    image2_data = base64.b64decode(image2_base64)
                except Exception as e:
                    return create_error_response(400, f"base64解码失败: {str(e)}")

                # 保存为临时文件
                image1_path, image2_path = self._two_images_process(
                    image1_data, image2_data
                )

                # 调用人脸匹配服务
                result = self.face_matcher.match_face_to_faces(
                    image1_path,
                    image2_path,
                    metric=metric,
                    threshold=threshold,
                    det_thresh=det_thresh,
                )

                # 删除临时文件
                try:
                    os.remove(image1_path)
                    os.remove(image2_path)
                except Exception as e:
                    self.logger.warning(f"删除临时文件失败: {str(e)}")
                return create_success_response("人脸匹配完成", result)
            except Exception as e:
                self.logger.error(f"人脸特征匹配失败: {str(e)}")
                return create_error_response(500, f"服务器内部错误: {str(e)}")

    def _param_data_check(self, data):
        """
        检查传入的数据参数是否有效。

        Args:
            data (dict): 包含图像数据和计算参数的字典。

        Returns:
            dict: 如果数据有效，返回None；如果数据无效，返回一个包含错误信息的字典。
        Raises:
            无
        """
        image1_base64 = data.get("image1_base64")
        image2_base64 = data.get("image2_base64")
        metric = data.get("metric", "cosine")  # 默认使用余弦相似度
        threshold = data.get("threshold", 0.6)  # 默认阈值为0.6

        # 验证参数
        if not image1_base64:
            return create_error_response(
                400,
                "参数image1_base64的值为空，请提供有效的base64编码的图片数据",
            )
        if not image2_base64:
            return create_error_response(
                400,
                "参数image2_base64的值为空，请提供有效的base64编码的图片数据",
            )

        # 验证metric参数
        if metric not in ValidMetrics:
            return create_error_response(
                400, f"参数metric的值无效，有效值为: {', '.join(ValidMetrics)}"
            )

        # 验证threshold参数
        if not isinstance(threshold, (int, float)) or not 0 <= threshold <= 1:
            return create_error_response(
                400, "参数similarity_threshold必须是0到1之间的数值"
            )

        return None
